/**
 *  TransactionalObject.java        22-ott-2009
 *   
 * Copyright (c) 2009 mentalsmash.org
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * 
 *  The use of the Apache License does not indicate that this project is
 *  affiliated with the Apache Software Foundation.
 */

package org.mentalsmash.tazio.transactions.objects;

import java.io.Serializable;

import org.mentalsmash.tazio.commons.identifiers.OID;
import org.mentalsmash.tazio.transactions.Transactional;

/**
 * <tt>TransactionalObject</tt> is the interface that is dynamically implemented
 * by objects that are transactionally shared through tazio.
 * <p>
 * A POJO can be shared in tazio if it respects the <i>Transactional Objects
 * Conventions (more documentation to come ... )</i>. <br />
 * Transactionality of objects is enforced in terms of Object's Properties. With
 * the term <i>Property</i> we indicate:
 * <ul>
 * <li>
 * A couple of public methods annotated respectively with
 * {@link org.mentalsmash.tazio.transactions.PropertySetter PropertySetter} and
 * {@link org.mentalsmash.tazio.transactions.PropertyGetter PropertyGetter}
 * having the same <code>name</code> attribute.</li>
 * </ul>
 * Modification to those object through the use of those properties are
 * guaranteed to be transactional. <br />
 * Notice that properties methods should not include any logic different from
 * settings object's fields, since we achieve transactionality by reading
 * parameters passed and returned by those methods.
 * 
 * </p>
 */
public interface TransactionalObject extends Serializable {

    /**
     * A version number that denotes a not initialized transactional object
     */
    final static long INITIAL_VERSION = 0;

    /**
     * Returns the {@link OID} uniquely associated to this
     * <tt>TransactionalObject</tt>
     * 
     * @return the {@link OID} uniquely associated to this
     *         <tt>TransactionalObject</tt>
     */
    OID getObjectIdentifier();
    
    String getLabel();

    /**
     * Returns the version of this <tt>TransactionalObject</tt>
     * <p>
     * The version of a <tt>TransactionalObject</tt> is the <i>sequence
     * number</i> of the last transaction that wrote the object
     * </p>
     * 
     * @return the version of this <tt>TransactionalObject</tt>
     */
    long getVersion();

    /**
     * Sets the version of this transactional object
     * <p>
     * The version number coincides with the sequence number of the last
     * transaction that wrote this object, and therefore it must be a
     * non-negative number
     * </p>
     * 
     * @param newVersiont
     *            he version of this transactional object
     */
    void setVersion(long newVersion);

    /**
     * Get an array containing the name of the properties of this
     * <tt>TransactionalObject</tt>
     * 
     * @return an array containing the name of the properties of this
     *         <tt>TransactionalObject</tt>
     */
    String[] getPropertyNames();

    /**
     * Gets the value of a Property of this transactional object.
     * <p>
     * <strong>Remember</strong> that the value of a Property for a
     * transactional object can either be a {@link TransactionalObject} itself
     * or a primitive type.
     * </p>
     * 
     * @param name
     *            the name of the property as defined in the annotations
     * @return the value of the property
     * @throws NoSuchPropertyException
     *             if no property having the provided <code>name</code> is found
     */
    Serializable getPropertyValue(String name) throws NoSuchPropertyException;

    /**
     * Sets the value of a property of this transactional object.
     * <p>
     * <strong>Remember</strong> that the value of a Property for a
     * transactional object can either be a {@link TransactionalObject} itself
     * or a primitive type.
     * </p>
     * 
     * @param namethe
     *            name of the property as defined in the annotations
     * @param value
     *            the value of the property to set
     * @throws NoSuchPropertyException
     *             if no property having the provided <code>name</code> is found
     * @throws IllegalArgumentException
     *             if <code>value</code> is of the wrong type for property
     */
    void setPropertyValue(String name, Serializable value)
	    throws NoSuchPropertyException;

    /**
     * Checks whether the property named <code>name</code> is read-only
     * 
     * @param name
     *            the name of the property to check against read-only-ness
     * @return true if the property named <code>name</code> is read-only
     * @throws NoSuchPropertyException
     *             if no property having the provided <code>name</code> is found
     */
    boolean isReadOnlyProperty(String name) throws NoSuchPropertyException;

    /**
     * Returns the type of the property named <code>name</code>. <br />
     * Notice that this is either an instance of an interface annotated with
     * {@link Transactional}, or a primitive type
     * 
     * @return the type of this property.
     * @throws NoSuchPropertyException
     *             if no property having the provided <code>name</code> is found
     */
    Class<?> getPropertyType(String name) throws NoSuchPropertyException;

    /**
     * Returns the interface of the TransactionalObject that is annotated with
     * the {@link org.mentalsmash.tazio.transactions.Transactional} annotation
     * 
     * @return
     */
    Class<?> getTransactionalInterface();

    /**
     * Gain exclusive access to the TransactionalObject. Must be followed by a
     * call to {@link #unlockObject()}
     */
    void lockObject();

    /**
     * Release the exclusive access to the TransactionalObject. Used after
     * {@link #lockObject()}
     */
    void unlockObject();
    
    /**
     * Returns 
     * @return
     */
    public Serializable getTargetObject();

}
